package com.xtm.exercise.base.A08Collection.A01list;

import cn.hutool.core.collection.ListUtil;
import com.google.common.collect.Lists;
import com.xtm.exercise.base.A08Collection.A02set.Person;
import com.xtm.exercise.base.A15jdk8Demo.java8.Student;
import com.xtm.exercise.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

/*
    java.util.List接口 extends Collection接口
    List接口的特点:
        1.有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123)
        2.有索引,包含了一些带索引的方法
        3.允许存储重复的元素

    ArrayList 的特性，直接回答 查询快，插入，删除慢

    List接口中带索引的方法(特有)
        - public void add(int index, E element): 将指定的元素，添加到该集合中的指定位置上。
        - public E get(int index):返回集合中指定位置的元素。
        - public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
        - public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
    注意:
        操作索引的时候,一定要防止索引越界异常
        IndexOutOfBoundsException:索引越界异常,集合会报
        ArrayIndexOutOfBoundsException:数组索引越界异常
        StringIndexOutOfBoundsException:字符串索引越界异常
 */
@Slf4j
public class Demo01List {
    public static void main(String[] args) {
        //创建一个List集合对象,多态
        List<String> list = new ArrayList<>();
        //使用add方法往集合中添加元素
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("a");

        String join1 = String.join(",", list);
        String join = StringUtils.join(list.toArray(), ",");
        System.out.println(join);
        System.out.println(join1);

        //打印集合
        System.out.println(list);//[a, b, c, d, a]  不是地址重写了toString

        //public void add(int index, E element): 将指定的元素，添加到该集合中的指定位置上。
        //在c和d之间添加一个itheima
        list.add(3,"itheima");//[a, b, c, itheima, d, a]
        System.out.println(list);

        //public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
        //移除元素
        String removeE = list.remove(2);
        System.out.println("被移除的元素:"+removeE);//被移除的元素:c
        System.out.println(list);//[a, b, itheima, d, a]

        //public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
        //把最后一个a,替换为A
        String setE = list.set(4, "A");
        System.out.println("被替换的元素:"+setE);//被替换的元素:a
        System.out.println(list);//[a, b, itheima, d, A]

        //List集合遍历有3种方式
        //使用普通的for循环
        for(int i=0; i<list.size(); i++){
            //public E get(int index):返回集合中指定位置的元素。
            String s = list.get(i);
            System.out.println(s);
        }
        System.out.println("--------使用迭代器------");
        //使用迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-------使用增强for-------");
        //使用增强for
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("------jdk1.8--------");
        //jdk1.8
        list.forEach(System.out::println);

        String r = list.get(5);//IndexOutOfBoundsException: Index 5 out-of-bounds for length 5
        System.out.println(r);

    }

    @Test
    public void test01(){
        //list中是否包含某个元素
        List<String> fruits = Arrays.asList("苹果", "香蕉", "桃子");

        if(fruits.contains("苹果")){
            System.out.println("有苹果");
        } else {
            System.out.println("没有苹果");
        }

//        判断list是否为空
//        空则返回true，非空则返回false
        if (fruits.isEmpty()) {
            System.out.println("空的");
        }else {
            System.out.println("不是空的");
        }

        //将集合转换为数组
        Object[] array = fruits.toArray();
        System.out.println(array);

        List<Object> list = Arrays.asList(array);
        System.out.println(list);
    }

    //list中根据索引将元素数值改变(替换)  注意 .set(index, element); 和 .add(index, element); 的不同
    @Test
    public void test02(){
        String a="白龙马", b="沙和尚", c="八戒", d="唐僧", e="悟空";
        List<String> people=new ArrayList<>();
        people.add(a);
        people.add(b);
        people.add(c);
        people.set(0, d);   //.set(index, element);     //将d唐僧放到list中索引为0的位置，替换a白龙马
        people.add(1, e);   //.add(index, element);     //将e悟空放到list中索引为1的位置,原来位置的b沙和尚后移一位

        //增强for循环遍历list
        for(String str:people){
            System.out.println(str);
        }
    }

    //list中查看（判断）元素的索引　
    //　注意：.indexOf（）； 和 lastIndexOf（）的不同；
    @Test
    public void test03(){
        List<String> names=new ArrayList<>();
        names.add("刘备");    //索引为0
        names.add("关羽");    //索引为1
        names.add("张飞");    //索引为2
        names.add("刘备");    //索引为3
        names.add("张飞");    //索引为4
        System.out.println(names.indexOf("刘备"));
        System.out.println(names.lastIndexOf("刘备"));
        System.out.println(names.indexOf("张飞"));
        System.out.println(names.lastIndexOf("张飞"));
    }

    //利用list中索引位置重新生成一个新的list（截取集合）
    //方法： .subList(fromIndex, toIndex)；　　.size() ； 该方法得到list中的元素数的和
    @Test
    public void test04(){
        List<String> phone=new ArrayList<>();
        phone.add("三星");    //索引为0
        phone.add("苹果");    //索引为1
        phone.add("锤子");    //索引为2
        phone.add("华为");    //索引为3
        phone.add("小米");    //索引为4
        //原list进行遍历
        for(String pho:phone){
            System.out.println(pho);
        }
        //生成新list
        phone=phone.subList(1, 4);  //.subList(fromIndex, toIndex)      //利用索引1-4的对象重新生成一个list，但是不包含索引为4的元素，4-1=3
        for (int i = 0; i < phone.size(); i++) { // phone.size() 该方法得到list中的元素数的和
            System.out.println("新的list包含的元素是"+phone.get(i));
        }
    }

    //对比两个list中的所有元素
    //两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象
    @Test
    public void test05(){
        List<String> fruits=new ArrayList<>();
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add("桃子");

        List<String> person=new ArrayList<>();
        person.add("苹果");
        person.add("香蕉");
        person.add("桃子");

        if (person.equals(fruits)) {
            System.out.println("两个list中的所有元素相同");
        }else {
            System.out.println("两个list中的所有元素不一样");
        }
        //2.
        if (person.hashCode()==fruits.hashCode()) {
            System.out.println("我们相同");
        }else {
            System.out.println("我们不一样");
        }
    }

    //集合类型转换
    @Test
    public void test06(){
        List<String> fruits=new ArrayList<>();
        fruits.add("苹果");
        fruits.add("香蕉");
        //1.默认类型
        List<Object> listsStrings=new ArrayList<>();
            for (int i = 0; i < fruits.size(); i++) {
            listsStrings.add(fruits.get(i));
        }
        //2.指定类型
        List<StringBuffer> lst=new ArrayList<>();
            for(String string:fruits){
            lst.add(new StringBuffer(string));
        }

        //3.map类型
        List<Map<String,Object>> list = new ArrayList<>();
        for (String string:fruits) {
            Map<String, Object> map = new HashMap<>();
            map.put(string,string);
            list.add(map);
        }
        System.out.println(list.toString());
    }

    //去重复
    @Test
    public void test07(){
        List<String> lst1=new ArrayList<>();
        lst1.add("aa");
        lst1.add("dd");
        lst1.add("ss");
        lst1.add("aa");
        lst1.add("ss");

        //方法 1.
        for (int i = 0; i <lst1.size()-1; i++) {
            for (int j = lst1.size()-1; j >i; j--) {
                if (lst1.get(j).equals(lst1.get(i))) {
                    lst1.remove(j);
                }
            }
        }
        System.out.println(lst1);

        //方法 2.
        List<String> lst2=new ArrayList<>();
        for (String s:lst1) {
            if (Collections.frequency(lst2, s)<1) {
                lst2.add(s);
            }
        }
        System.out.println(lst2);
    }

    //两个list相互减（移除）  从一个list中移除另一个list中有的元素
    @Test
    public void test08(){
        List<Object> list01 = new ArrayList<>();
        list01.add("1");
        list01.add("2");
        list01.add("5");

        List<Object> list02 = new ArrayList<>();
        list02.add("1");
        list02.add("2");
        list02.add("3");
        list02.add("4");

        boolean b = list02.removeAll(list01);
        System.out.println(list02);

    }

    @Test
    public void test09(){
        List<Object> list = new ArrayList<>();

        list.add("1");
        list.add(null);
        list.add(null);

        System.out.println(list); //[1, null, null]

    }

    /**
     * 对集合中的元素位置进行交换
     */
    @Test
    public void test10(){
        List<Object> list01 = new ArrayList<>();
        list01.add("1");
        list01.add("2");
        list01.add("3");
        list01.add("4");
        list01.add("5");

        // 对集合中的元素位置进行交换
        Collections.swap(list01,0,4);
        System.out.println(list01);

        list01.clear();
        System.out.println(list01);
    }

    // 判断Person集合中的name属性有没有重复
    @Test
    public void test12(){
        List<Person> personList = new ArrayList<Person>();
        Person p1 = new Person();
        p1.setName("张三");
        p1.setAge(1);
        personList.add(p1);
        Person p2 = new Person();
        p2.setName("张三");
        p2.setAge(1);
        personList.add(p2);
        Person p3 = new Person();
        p3.setName("张三");
        p3.setAge(12);
        personList.add(p3);

        List<Integer> stringList = personList.stream().map(Person::getAge)
                .collect(Collectors.toList());
        long count = stringList.stream().distinct().count();
        if (stringList.size() == count) {
            System.out.println("没有重复元素");
        } else {
            System.out.println("有重复元素");
        }

    }

    @Test
    public void test4(){
        List<Long> loadedStatus = Lists.newArrayList(1L,2L);
        List<Long> signedStatus = Lists.newArrayList(2L);
        if(loadedStatus.contains(2L)){
           log.info("包含");
        }
    }

    // 1.一个集合根据对象属性，去除重复数据
    // 2.判断一个集合是否有重复数据
    @Test
    public void test13(){
        List<Student> studentList = Lists.newArrayList();
        Student student = new Student("laodb3", 32);
        Student student1 = new Student("laodb1", 32);
        Student student2 = new Student("laodb2", 32);
        Student student3 = new Student("laodb1", 32);
        studentList.add(student);
        studentList.add(student1);
        studentList.add(student2);
        studentList.add(student3);
        List<Student> students = studentList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(s -> s.getAge() +";"+s.getName()))),ArrayList::new));
        System.out.println(students);
        if(studentList.size() != students.size()){
            System.out.println("studentList集合有重复数据");
        }
    }

    // 两个集合，比较相同属性的数据，大的集合减去小的集合，得到新的集合
    @Test
    public void test14(){
        List<Integer> of = ListUtil.of(1, 2);
        log.info("of:{}", of);


        List<Student> studentList = Lists.newArrayList();
        Student student = new Student("laodb3", 32);
        Student student1 = new Student("laodb1", 32);
        Student student2 = new Student("laodb2", 32);
        Student student3 = new Student("laodb1", 32);
        studentList.add(student);
        studentList.add(student1);
        studentList.add(student2);
        studentList.add(student3);


        List<Student> stu2List = Lists.newArrayList();
        Student stud = new Student("laodb3", 32);
        stu2List.add(stud);

        boolean b = studentList.removeAll(stu2List);

        List<Student> noSetPurchaseLimitList = studentList.stream()
                .filter(add -> stu2List.stream().noneMatch(all ->  Objects.equals(add.getName() + add.getAge(), all.getName() + all.getAge()) ) ).collect(Collectors.toList());

        System.out.println(noSetPurchaseLimitList);


    }

    @Test
    public void test90() throws UnsupportedEncodingException {
        String formStr = "accessMerchantNo = 1000000001 & custNo = 030 c642645774db2b187339c09241bfc & custName = %E6%B5%8B%E8%AF%95 % E5 % 85 % AC % E5 % 8 F % B8 & unifiedSocialCode = 91120000103061295 A & certNo = & orgCertCode = & taxRegCode = & entScope = & certArea = & expiryDate = & tel = 13072029809 & webAddr = & fullAddr = % E7 % 94 % 98 % E8 % 82 % 83 % E7 % 9 C % 81 + % E9 % 99 % 87 % E5 % 8 D % 97 % E5 % B8 % 82 + % E7 % A4 % BC % E5 % 8E % BF + 123 & asynUrl = http % 3 A % 2 F % 2 Fjtqy10.esgmall.com % 3 A19018 % 2 Fadmin % 2 Fcontrac % 2 Fcontrac & version = V1 .0 & signData = MIIDOQYJKoZIhvcNAQcCoIIDKjCCAyYCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCAfYwggHyMIIBW6ADAgECAgEaMA0GCSqGSIb3DQEBBQUAMGAxETAPBgNVBAoTCGh0amMuSW5jMR0wGwYDVQQLExRodGpjIHNlY3VyaXR5IGNlbnRlcjEPMA0GA1UEAxMGSFRKQ0NBMRswGQYJKoZIhvcNAQkBFgxodGpjQDE2My5jb20wHhcNMTYwNDI4MDczMjM5WhcNMjYwNDI2MDczMjM5WjAPMQ0wCwYDVQQDDARib3NwMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxromhD2ZcYkJTbv7hAjQCCk6eC7erZtI9uQcfT8qWs76Ql1AmSU4B9Xulko4Ln5K4RYDWsViz % 2 FWOzPay6FcEaH % 2 BeupdIg1pwGP9Q % 2 Bz2sL4e1 % 2 Feno % 2 F % 2 FNs12w0KqcCD3ZCC % 2 FnCgQuCvIRn2lVvPiuClfpQsbQsbcStqSPWCek46sQIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBBQUAA4GBAIQ2ai % 2 Fe8KTPLNAqITHci % 2 BfiLjY44mDGtIrduRcF6uHNsIA8msABcg7vjXlkR7txBtizNX2qtdHal3Imzkln6R % 2 FjbV % 2 BAL9mDwu1EyPpoQHadzK9CXLABQ5aZc2fEytk % 2 FMjR7zCh2fPOSla4ZOwfSVHCax % 2 Fi9yoCj % 2 FdEKbKdtwI1 % 2 BMYIBCzCCAQcCAQEwZTBgMREwDwYDVQQKEwhodGpjLkluYzEdMBsGA1UECxMUaHRqYyBzZWN1cml0eSBjZW50ZXIxDzANBgNVBAMTBkhUSkNDQTEbMBkGCSqGSIb3DQEJARYMaHRqY0AxNjMuY29tAgEaMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYA3UHqThWzNU8E6888ao4mxpkgT0 % 2 FmyXh2HvT26JXFP % 2 BSV6wr % 2 Fz7exSRJCTwCushFTrfhzVyd % 2 FSsqusA3nL8 % 2 FzWWe3SG7 % 2 B % 2 Fzc4 % 2 BT4IiIH3auHrdnnQ619tVbPmWLBkrLGM5Pz8ytsKszDrJrYX6OSxrCbsPsX % 2 FBWIptMMlzS5dqCQ % 3 D % 3 D & productCode = 1 & synUrl = http % 3 A % 2 F % 2 Fjtqy10.esgmall.com % 3 A19018 % 2 Fseller % 2 FsupplierjoinIn % 2 Fcheck";
        StringBuffer sb = new StringBuffer();
        String[] arr = formStr.split("&");
        List<String> list = Arrays.asList(arr);

        if(list.size() > 0){
            for (int i = 0; i < list.size(); i++) {
                String s = list.get(i);
                //
                String[] splitArr = s.split("=");
                String strKey = splitArr[0].trim();
                String strValue = splitArr[1].replace(" ", "");
                String decode= URLDecoder.decode(strValue,"utf-8");
                //
                if("accessMerchantNo".equals(strKey) || "custNo".equals(strKey) || "custName".equals(strKey) || "orgCertCode".equals(strKey) ||
                    "taxRegCode".equals(strKey) || "entScope".equals(strKey) || "certArea".equals(strKey) || "expiryDate".equals(strKey) ||
                    "unifiedSocialCode".equals(strKey) || "certNo".equals(strKey) || "orgCertCode".equals(strKey) || "tel".equals(strKey) ||
                    "webAddr".equals(strKey) || "fullAddr".equals(strKey) || "asynUrl".equals(strKey) || "version".equals(strKey) ||
                    "signData".equals(strKey) || "productCode".equals(strKey) || "synUrl".equals(strKey)
                ){
                    s = strKey + " = " + decode;
                }
                sb.append(s + " & ");
            }
        }

        String substring = sb.substring(0, sb.length() - 2);
        System.out.println(substring);
    }

}
